﻿/*
 * MiniFox Studio since 2010
 * minifox.js v3.0.0
 * Docs & License: http://hanko12.com
 * 作者: 漢口十二
 */
+function (global, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    }
    else {
        var $ = jQuery || require('jquery');
        if (typeof exports === 'object' && typeof module !== 'undefined') {
            module.exports = factory($);
        }
        else {
            global.MiniFox = factory($);
        }
    }
    console.log('minifox.js v3.0.0 \nSince 2010 Copyright © MiniFox Studio All rights reserved. 漢口十二 8823428@qq.com ^_^');
}(this, function ($) {
    "use strict";
    var userAgent = navigator.userAgent;
    var isOpera = userAgent.indexOf("Opera") > -1;
    var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera;
    if (isIE) {
        var IE9, IE55, IE6, IE7, IE8;
        IE9 = IE55 = IE6 = IE7 = IE8 = false;
        var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
        reIE.test(userAgent);
        var fIEVersion = parseFloat(RegExp["$1"]);
        IE55 = fIEVersion == 5.5;
        IE6 = fIEVersion == 6.0;
        IE7 = fIEVersion == 7.0;
        IE8 = fIEVersion == 8.0;
        IE9 = fIEVersion == 9.0;
        if (IE55 || IE6 || IE7 || IE8 || IE9) {
            alert("请在IE10或更高版本的浏览器，推荐使用Microsoft Edge、Chrome、Firefox、Safari等支持HTML5内核浏览器！");
            return;
        }
    }
    /***************************loading begin**************************/
    (function ($) {
        var initialized = false;
        var pluginName = "process";
        var defaults = {
            loadingText: "处理中，请稍候...",
            autoShow: true
        };
        $.fn.process = function () {
            var method = arguments[0];
            var func = methods[method];
            var args = arguments;
            if (func && $.isFunction(func)) {
                args = Array.prototype.slice.call(args, 1);
            } else if ($.isPlainObject(method) || !method) {
                func = methods.init;
            } else {
                $.error('方法名 "' + method + '" 不存在。');
                return this;
            }
            return func.apply(this, args);
        };

        //初始化设置
        var createSetting = function (opt) {
            var plugin = $(this);
            var options = plugin.data(pluginName);

            if ($.type(options) == 'undefined') {
                options = $.extend({}, defaults, opt);
            } else {
                options = $.extend({}, options, opt);
            }

            plugin.data(pluginName, options);
            return options;
        };

        var methods = {
            init: function (opt) {
                return $(this).each(function () {
                    var options = createSetting.apply(this, [opt]);
                    if (!initialized) {
                        var overlay = $('<div class="ui-overlay process-overlay"><div class="ui-widget-overlay"></div></div>');
                        overlay.appendTo(this);
                        var loadingBar = $('<div class="loading-bar ui-dialog ui-widget ui-widget-content ui-corner-all ui-dialog-content"></div>');
                        loadingBar.appendTo(this);
                        var loadingicon = $('<div class="loading"></div>');
                        loadingicon.appendTo(loadingBar);
                        var loadingtxt = $('<div class="loading-txt"></div>');
                        loadingtxt.appendTo(loadingicon);
                        var screenRect = { width: overlay.find(".ui-widget-overlay").width(), height: overlay.find(".ui-widget-overlay").height() };
                        var loadingBaroffset = { top: (screenRect.height - loadingBar.outerHeight()) / 2, left: (screenRect.width - loadingBar.outerWidth()) / 2 };
                        loadingBar.offset(loadingBaroffset);
                        if (!options.autoShow)
                            methods.hide.apply(this, [opt]);
                        initialized = true;
                    }

                });
            },
            show: function (opt, txt) {
                if ($.type(opt) == "string") {
                    txt = opt;
                    opt = defaults;
                }
                if (!initialized) {
                    methods.init.apply(this, [opt]);
                }
                var plugin = $(this);
                var options = plugin.data(pluginName);
                var overlay = $(this).find('.process-overlay');
                var z_index = overlay.find('.ui-widget-overlay').css("z-index");
                var loadingBar = $(this).find('.loading-bar');
                loadingBar.css("z-index", z_index + 1);
                $(this).find('.loading-txt').text(txt || options.loadingText);
                overlay.show('fade');
                loadingBar.show('fade');
            },
            hide: function (opt) {
                return $(this).each(function () {
                    var overlay = $(this).find('.process-overlay');
                    var loadingBar = $(this).find('.loading-bar');

                    overlay.hide('fade');
                    loadingBar.hide('fade');
                });
            },
            destroy: function (opt) {
                return $(this).each(function () {
                    var $this = $(this);
                    $this.removeData(pluginName);

                    var overlay = $this.find('.process-overlay');
                    var loadingBar = $this.find('.loading-bar');

                    overlay.remove();
                    loadingBar.remove();
                });
            }
        };

    })($);

    /***************************loading end **************************/

    /***************************弹出框 begin**************************/
    $.alert = function (msg, title, closeEvent) {
        title = title || "系统消息";
        var dialog = $('<div><p>' + msg + '</p></div>');
        var that = this;
        dialog.appendTo(document.body);
        dialog.dialog({
            title: title,
            autoOpen: true,
            width: 400,
            show: { effect: "fade", duration: 200 },
            hide: { effect: "fade", duration: 200 },
            resizable: false,
            modal: true,
            buttons: { "确定": function () { $(this).dialog("close"); } },
            close: function () {
                $(this).remove();
                if (closeEvent)
                    closeEvent.apply(that);
            }
        });
    };
    $.confirm = function (msg, title, acceptEvent, rejectEvent) {
        title = title || "提示";
        var dialog = $('<div><p>' + msg + '</p></div>');
        var that = this;
        dialog.appendTo(document.body);
        dialog.dialog({
            title: title,
            autoOpen: true,
            width: 400,
            show: { effect: "fade", duration: 200 },
            hide: { effect: "fade", duration: 200 },
            resizable: false,
            modal: true,
            buttons: [
                { text: "是", click: function () { if (acceptEvent) acceptEvent.apply(that); $(this).dialog("close"); } },
                { text: "否", click: function () { if (rejectEvent) rejectEvent.apply(that); $(this).dialog("close"); } }
            ],
            close: function () {
                $(this).remove();
                if (rejectEvent)
                    rejectEvent.apply(that);
            }
        });
    };

    /***************************弹出框 end  **************************/

    /***************************数组类型扩展**************************/

    /**
     * 累加求和
     * @param {any} key
     * @returns
     */
    Array.prototype.sum = function (key) {
        var total = 0;
        this.forEach(function (item) {
            if (key) {

                var val;
                if (typeof key == 'function') {
                    val = key(item);
                }
                else {
                    val = item[key];
                }
                if (typeof val == 'number') {
                    total += val;
                }
            }
        });
        return total;
    };
    /**
     * 向集合中插入一项
     * @param {any} item 元素
     * @param {Number} i 插入的位置
     * @returns
     */
    Array.prototype.insert = function (item, i) {
        if (typeof i != 'number')
            return;

        if (i >= 0 && i < this.length)
            this.splice(i, 0, item);
        else
            this.push(item);
    };
    /**
     * 从集合中删除指定元素
     * @param {any} item
     */
    Array.prototype.remove = function (item) {

        for (var i = 0; i < this.length; i++) {
            if (typeof item == 'function' && item(this[i])) {
                this.splice(i, 1);
                break;
            }
            else if (this[i] === item) {
                this.splice(i, 1);
                break;
            }
        }
    };
    /**
     * 按条件查找
     * @param {Function} conditionCallback
     * @returns
     */
    Array.prototype.where = function (conditionCallback) {
        var arr = [];
        for (var i = 0; i < this.length; i++) {
            if (conditionCallback && typeof conditionCallback == 'function' && conditionCallback(this[i]))
                arr.push(this[i]);
        }
        return arr;
    };
    /**
     * 按唯一键查找
     * @param {Function} conditionCallback
     * @returns
     */
    Array.prototype.singleOrDefault = function (conditionCallback) {
        for (var i = 0; i < this.length; i++) {
            if (conditionCallback && typeof conditionCallback == 'function' && conditionCallback(this[i]))
                return this[i];
        }
        return null;
    };
    /**
     * 按条件检查
     * @param {Function} conditionCallback
     * @returns
     */
    Array.prototype.any = function (conditionCallback) {
        for (var i = 0; i < this.length; i++) {
            if (conditionCallback && typeof conditionCallback == 'function' && conditionCallback(this[i]))
                return true;
        }
        return false;
    };
    /**
     * 
     * @param {Function} callback
     * @returns
     */
    Array.prototype.select = function (callback) {
        var result = [];
        for (var i = 0; i < this.length; i++) {
            if (callback && typeof callback == 'function') {
                result.push(callback(this[i]));
            }
        }
        return result;
    };
    /***************************日期类型格式化扩展**************************/

    /**
     * 日期格式化
     * @param {String} fmt 格式化表达式，默认：yyyy-MM-dd HH:mm:ss
     * @returns
     */
    Date.prototype.pattern = function (fmt) {
        fmt = fmt || "yyyy-MM-dd HH:mm:ss";
        var o = {
            "M+": this.getMonth() + 1, //月份           
            "d+": this.getDate(), //日           
            "h+": this.getHours() % 12 == 0 ? 12 : this.getHours() % 12, //小时           
            "H+": this.getHours(), //小时           
            "m+": this.getMinutes(), //分           
            "s+": this.getSeconds(), //秒           
            "q+": Math.floor((this.getMonth() + 3) / 3), //季度           
            "S": this.getMilliseconds() //毫秒           
        };
        var week = {
            "0": "/u65e5",
            "1": "/u4e00",
            "2": "/u4e8c",
            "3": "/u4e09",
            "4": "/u56db",
            "5": "/u4e94",
            "6": "/u516d"
        };
        if (/(y+)/.test(fmt)) {
            fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
        }
        if (/(E+)/.test(fmt)) {
            fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "/u661f/u671f" : "/u5468") : "") + week[this.getDay() + ""]);
        }
        for (var k in o) {
            if (new RegExp("(" + k + ")").test(fmt)) {
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
            }
        }
        return fmt;
    };

    /***************************数字类型扩展**************************/

    /**
     * 前置自动补零
     * @param {Number} length 补零长度
     * @returns
     */
    Number.prototype.PrefixInteger = function (length) {
        var num = this;
        return (Array(length).join('0') + num).slice(-length);
    };
    /**
     * 保留小数位
     * @param {Number} precision
     * @returns
     */
    Number.prototype.toFixed = function (precision) {
        var result,
            dot;
        if (isNaN(this))
            return NaN;
        var str = this + '';
        var reg = new RegExp("\\.(\\d{" + precision + "})");
        if (/[^\-\.\d]/.test(str) || !reg.test(str)) {
            result = str;
        } else {
            str = str.replace(reg, "$1.");
            result = Math.round(parseFloat(str)) / Math.pow(10, precision) + '';
        }
        /*
        * 处理进位后无小数
        */
        dot = result.indexOf(".");
        if (dot < 0) {
            result += '.';
            dot = result.indexOf(".");
        }
        /*
        * 处理多次进位
        */
        var len = result.length - (dot + 1);
        if (len < precision) {
            for (var i = 0; i < precision - len; i++) {
                result += 0;
            }
        }
        return result;
    };

    /***************************字符类型扩展**************************/
    /**
     * 判断字符串是否为日期
     * @returns
     */
    String.prototype.isDate = function () {
        var valid = /\/Date\((\-?\d+)\)\//i.test(this);
        valid = valid || /^\d{4}\-\d{2}\-\d{2} \d{4}:\d{2}:\d{2}$/i.test(this);
        return valid;
    };
    /**
     * 将字符串转换为javascript日期类型
     * @returns
     */
    String.prototype.toDate = function () {
        if (/\/Date\((\-?\d+)\)\//i.test(this)) {
            var date = eval(this.replace(/\/Date\((\-?\d+)\)\//i, "new Date($1)"));
            return date;
        }
        else if (/^\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}$/i.test(this)) {

            var date = new Date(this.replace(/-/g, '/'));
            return date;
        }
        else if (/^\d{4}\-\d{2}\-\d{2}$/i.test(this)) {

            var date = new Date(this.replace(/-/g, '/'));
            return date;
        }
        return this;
    };
    /**
     * 将字符串进行日期格式化
     * @param {String} fmt
     * @returns
     */
    String.prototype.pattern = function (fmt) {
        var date = this.toDate();
        if (date instanceof Date)
            return date.pattern(fmt);
        else
            return date;
    };
    /**
     * 判断字符串是否为Url
     * @returns
     */
    String.prototype.isUrl = function () {
        return /^(https?|ftp|file):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]$/.test(this);
    };
    /**
     * 判断字符串是否为数字
     * @returns
     */
    String.prototype.isNumber = function () {
        return /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(this);
    };
    /**
     * 将字符串转换为javascript数字类型
     * @returns
     */
    String.prototype.toNumber = function (digits) {
        return new Number(this).toFixed(digits);
    };
    /**
     * 将字符串进行Url编码
     * @returns
     */
    String.prototype.urlEncode = function () {
        return encodeURIComponent(this);
    };
    /**
     * 将字符串进行Url解码
     * @returns
     */
    String.prototype.urlDecode = function () {
        return decodeURIComponent(this);
    };
    /**
     * 移除字符串右侧指定字符
     * @returns
     */
    String.prototype.rightTrim = function (s) {
        var str = this;
        while (str.substring(str.lastIndexOf(s)) === s) {
            str = str.substring(0, str.lastIndexOf(s));
        }
        return str;
    };
    /**
     * 移除字符串左侧指定字符
     * @returns
     */
    String.prototype.leftTrim = function (s) {
        var str = this;
        while (str.indexOf(s) == 0) {
            str = str.substring(str.indexOf(s) + s.length);
        }
        return str;
    };
    /**
     * 移除字符串两侧指定字符
     * @returns
     */
    String.prototype.trim = function (s) {
        return this.leftTrim(s).rightTrim(s);
    };
    /**
     * 判断字符串是否以指定字符开头
     * @returns
     */
    String.prototype.startsWith = function (s) {
        return this.indexOf(s) === 0;
    };
    /**
     * 判断字符串是否以指定字符结尾
     * @returns
     */
    String.prototype.endsWith = function (s) {
        var i = this.lastIndexOf(s);
        return this.length - i === s.length;
    };


    /***************************URI类型**************************/
    String.prototype.toUri = function () {
        return new Uri(this);
    };

    var Uri = (function () {
        function Uri(uriString) {
            uriString = uriString || window.location.href;
            if (!uriString.startsWith("http://") && !uriString.startsWith("https://"))
                uriString = `${window.location.origin}/${uriString.trim('/')}`;
            if (typeof uriString != 'string' || !uriString.isUrl()) {
                return null;
            }

            var segments = uriString.split('#');
            var fullpathSegments = segments[0].split('?');
            var schemaSegments = fullpathSegments[0].split('://');
            this.protocal = schemaSegments[0];

            var pathSegments = schemaSegments[1].split('/');
            var hostSegments = pathSegments[0].split(':');
            this.host = hostSegments[0];
            this.port = hostSegments[1] || '';
            this.portNumber = 0;
            if (this.port) {
                this.portNumber = Number(this.port);
            }
            else {

                switch (this.protocal.toLowerCase()) {
                    case 'ftp':
                        this.portNumber = 21;
                        break;
                    case 'https':
                        this.portNumber = 443;
                        break;
                    case 'http':
                    default:
                        this.portNumber = 80;
                        break;
                }
            }

            pathSegments.remove(pathSegments[0]);
            this.path = (pathSegments && pathSegments.length > 0) ? ('/' + pathSegments.join('/')) : "";
            this.search = fullpathSegments[1];
            this.hash = segments[1];
            this.params = {};
            if (this.search) {
                var parArray = this.search.split('&');
                for (var i = 0; i < parArray.length; i++) {
                    var arr = parArray[i].split('=');
                    var name = arr[0];
                    var val = arr[1] || "";
                    this.params[name] = val.urlDecode();
                }
            }
        }
        /**
         * 为uri对象添加query参数
         * @param {String} name 参数名
         * @param {any} value 参数值(无需Url编码)
         */
        Uri.prototype.addParam = function (name, value) {
            this.params = this.params || {};
            this.params[name] = value;
        };
        /**
         * 为uri对象添加query参数
         * @param {any} dictionary 参数键值对(无需Url编码)
         */
        Uri.prototype.addParams = function (dictionary) {
            for (var name in dictionary) {
                this.addParam(name, dictionary[name])
            }
        };
        /**
         * 为uri对象移除指定的query参数
         * @param {String} name 参数名
         */
        Uri.prototype.remove = function (name) {
            if (this.params)
                delete this.params[name];
        };
        /**
         * 将Uri对象转换为String，转换过程中将对Query参数值执行Url编码
         * @returns
         */
        Uri.prototype.toString = function () {
            if (this.params) {

                var params = [];
                for (var name in this.params) {
                    var val = this.params[name];
                    params.push(name + "=" + val.toString().urlEncode());
                }
                this.search = params.join('&');
            }
            return this.protocal + "://" + this.host + (this.port ? (":" + this.port) : "") + (this.path ? this.path : "") + (this.search ? ("?" + this.search) : "") + (this.hash ? ("#" + this.hash) : "");
        };

        return Uri;
    })();

    /***************************URI类型 end *******************/

    /*************************** Task **************************/
    var Task = (function () {
        function Task(name, options) {
            this.name = name;
            //this.url = options.url;
            //this.method = options.method;
            //this.postData = options.postData;
            this.context = options.context || this;
            this.arguments = options.arguments || {};
            this.promise = options.promise;
            this.onAction = options.onAction;
            this.onError = options.onError;
            this.once = options.once || false; //一次性的
            this.retryTimes = options.retryTimes; //重试次数
            this.interval = options.interval; //重复间隔
            this.delay = options.delay || 0; //延时多少秒开始
            this.retried = this.retryTimes;
            this.running = false;
        }

        Task.prototype.polling = function () {
            if (!this.running)
                return;

            if (this.promise && $.isFunction(this.promise)) {
                var callee;
                if (this.promise.length > 1) {
                    if (this.arguments instanceof Array)
                        callee = this.promise.apply(this, this.arguments);
                    else
                        callee = this.promise(this.arguments);
                }
                else {
                    callee = this.promise(this.arguments);
                }
                callee.then((function (task) {
                    return function () {
                        if (task.retried < 3) task.retried = 3;
                        if ($.isFunction(task.onAction)) task.onAction.apply(task.context, arguments);
                        if (task.once) {
                            task.running = false;
                            return;
                        }
                        var func = debounce(task.polling, task.interval);
                        func.apply(task);

                    };
                })(this)).catch((function (task) {
                    return function () {
                        if ($.isFunction(task.onError)) task.onError.apply(task, arguments);
                        if (task.retried > 0) {
                            var func = debounce(task.polling, task.interval);
                            func.apply(task);
                            task.retried--;
                        }
                        else {
                            task.running = false;
                        }
                    };
                })(this));
            }
            else {
                try {
                    if (this.retried < 3) this.retried = 3;
                    if ($.isFunction(this.onAction))
                        this.onAction.apply(this.context, [this.arguments]);
                    if (this.once) {
                        this.running = false;
                        return;
                    }
                    var func = debounce(this.polling, this.interval);
                    func.apply(this);
                }
                catch (e) {
                    if ($.isFunction(this.onError)) this.onError.apply(this.context, [e]);
                    if (this.retried > 0) {
                        var func = debounce(this.polling, this.interval);
                        func.apply(this);
                        this.retried--;
                    }
                    else {
                        this.running = false;
                    }
                }
            }
        };

        Task.prototype.start = function (delay) {
            this.retried = this.retryTimes;
            this.running = true;
            if (delay > 0)
                debounce(this.polling, delay).apply(this);
            else if (this.delay > 0)
                debounce(this.polling, this.delay).apply(this);
            else
                this.polling();
        };

        Task.prototype.stop = function () {

            this.running = false;
            this.retried = 0;
        };

        Task.prototype.restart = function () {

            this.stop();
            this.start();
        };

        return Task;
    })();

    var TaskPool = (function () {
        function TaskPool(options) {
            this.defaults = {
                retryTimes: 3,
                delay: 0,
                interval: 5000,
                method: 'get'
            };
            this.options = $.extend({}, this.defaults, options);

            this.taskList = {};
        }

        TaskPool.prototype.allStart = function () {
            for (var name in this.taskList) {
                this.taskList[name].start();
            }
        };

        TaskPool.prototype.addTask = function (task, autoStart) {
            this.taskList[task.name] = task;

            task.retryTimes = task.retryTimes || this.options.retryTimes;
            task.interval = task.interval || this.options.interval;
            task.method = task.method || this.options.method;
            task.delay = task.delay || this.options.delay;
            if (autoStart) task.start();
        };

        TaskPool.prototype.deleteTask = function (name) {
            this.taskList[name].stop();
            delete this.taskList[name];
        };

        TaskPool.prototype.getTask = function (name) {
            return this.taskList[name];
        };

        return TaskPool;
    })();

    /*************************** Task end **************************/

    /*************************** Agent begin **************************/

    // 
    var Agent = (function () {
        /**
         * 跨域访问父框架代理对象
         * @param {String} domain 框架域名
         * @param {any} objectName
         */
        function Agent(domain, objectName) {
            this.domain = domain || (window.location.protocol + "//" + window.location.host);
            this.objectName = objectName;
        }

        Agent.prototype.sendMessage = function (methodName, params) {
            var data = {
                objectName: this.objectName,
                methodName: methodName,
                arguments: params
            };
            window.parent.postMessage(data, this.domain);
        };
        return Agent;
    })();
    /*************************** Agent end **************************/

    /*************************** container begin **************************/
    function extend(base, ctor) {
        var container = function () {
            base.apply(this, arguments);
            ctor.apply(this, arguments);
            if ($.isFunction(this.domInit)) this.domInit();
        };
        container.prototype = new base();
        return container;
    }
    function inherit(container, key, property, readonly) {
        var obj = key ? container.$parent[key] : container.$parent;
        var descriptor = {
            configurable: true,
            enumerable: false,
            get: function () {
                return obj[property];
            },
        };
        if (!readonly) {
            descriptor.set = function (newVal) {
                return obj[property] = newVal;
            }
        }
        Object.defineProperty(key ? container[key] : container, property, descriptor);
    }
    function recursion(container, key, property, readonly) {
        var obj = key ? container[key] : container;
        if (obj) {

            var descriptor = {
                configurable: false,
                enumerable: false,
                get: function () {
                    return container[property];
                },
            };
            if (!readonly) {
                descriptor.set = function (newVal) {
                    container[property] = newVal;
                }
            }

            if (obj instanceof Array) {
                obj.forEach(function (item) {
                    Object.defineProperty(item, property, descriptor);
                    recursion(item, key, property, readonly);
                });
            }
            else if (obj instanceof Object) {
                for (var name in obj) {
                    var item = obj[name];

                    Object.defineProperty(item, property, descriptor);
                    recursion(item, key, property, readonly);
                }
            }
        }
    }

    var Container = (function () {
        //私有方法
        function create() {
            this.createComponents();
            if ($.isFunction(this.created)) {
                this.created();
            }
        }
        function loadTemplate() {
            if (this.template) {
                this.$template = $(this.template);

                this._template = this.$template.html();
                $.template(this._id, this._template);
            }
        }
        var __builtin_members = ["created", "watcher", "updated", "resized", "components"];
        //构造base
        var container = function (options, parent) {
            if (options) {

                this._id = createGUID();
                this._updated = false;
                this.$parent = parent;//父组件
                this.components = {};//子组件
                this.watcher = {};//监视器

                this.init();//初始化自有属性
                this.$options = this.mergeOptions(options);//合并选项
                this.$options.element = this.$options.element ? this.$options.element : '#' + this._id;

                //属性拷贝
                +function (container) {

                    var updating = debounce(container.update, 100);
                    for (var property in container.$options) {
                        var propertyVal = container.$options[property];
                        if (property.indexOf('$') === 0 || __builtin_members.any(property)) //$开头的或内置属性的，不拷贝
                            continue;

                        container[property] = propertyVal;

                        observer(container, property, propertyVal, (function (property) {

                            return function (val, newVal) {
                                if (val !== newVal) {
                                    container.$options[property] = newVal;//直通选项
                                    var watchItem = container.watcher[property];
                                    if (watchItem) {
                                        if ($.isFunction(watchItem.onchange))//监视器中的属性改变定制刷新
                                            return watchItem.onchange.apply(container);
                                    }
                                    else {
                                        //未监视的属性改变刷新本组件
                                        return updating.apply(container);
                                    }
                                }
                                return true;
                            }
                        })(property));
                    }

                    Object.defineProperty(container, "$element", {
                        configurable: false,
                        enumerable: false,
                        get: function () {
                            var el = $(container.element);
                            if (el.length <= 0)
                                el = $("#" + container._id);
                            return el;
                        }
                    });
                }(this);

                loadTemplate.apply(this);
                this.render();
                create.apply(this);
                this.layout();
            }
        };
        //初始化
        container.prototype.init = function () {

        };
        //用于重写，与默认选项合并返回
        container.prototype.mergeOptions = function (options) {
            return options;
        };
        //初始化，用于重写，创建jquery事件
        container.prototype.domInit = function () {
        };
        //创建子组件
        container.prototype.createComponents = function () {
            if (this.$options.components && this.$options.components instanceof Object) {

                for (var name in this.$options.components) {
                    var component = this.$options.components[name];
                    if (component.type) {
                        if (typeof component.type === 'function') {
                            this.components[name] = new component.type();
                        }
                    }
                }
            }
        };
        container.prototype.height = function (v) {
            if (v)
                return this.$element.height(v);
            else
                return this.$element.height();
        };
        container.prototype.width = function (v) {
            if (v)
                return this.$element.width(v);
            else
                return this.$element.width();
        };
        container.prototype.innerHeight = function () {
            return this.$element.innerHeight();
        };
        container.prototype.innerWidth = function () {
            return this.$element.innerWidth();
        };
        container.prototype.outerHeight = function () {
            return this.$element.outerHeight(true);
        };
        container.prototype.outerWidth = function () {
            return this.$element.outerWidth(true);
        };
        //呈现
        container.prototype.render = function () {

            if (this._template) {
                var $html = $.tmpl(this._id, this.$options);

                if (this.$element.length > 0) {
                    if (this.replaceMode) {
                        if (this.element === '#' + this._id) {

                            if ($html.length === 1) {
                                $html.attr("id", this._id);
                            }
                            else {
                                var wrapElement = $('<div id="' + this._id + '"></div>');
                                $html = wrapElement.html($html);
                            }
                        }
                        $html.replaceAll(this.$element);
                    }
                    else {
                        this.$element.html($html);
                    }
                }
                else {

                    if ($html.length === 1) {
                        $html.attr("id", this._id);
                    }
                    else {
                        var wrapElement = $('<div id="' + this._id + '"></div>');
                        $html = wrapElement.html($html);
                    }
                    $html.appendTo(this.$parent.$element);
                    this.replaceMode = true;
                }
            }
        };
        container.prototype.update = function () {

            this.render();
            for (var name in this.components) {
                this.components[name].update();
            }

            if ($.isFunction(this.updated)) {
                this.updated();
            }
            this._updated = true;
        };
        container.prototype.resize = function () {
            for (var name in this.components) {
                this.components[name].resize();
            }

            this.layout();
            if ($.isFunction(this.resized))
                this.resized();
        };
        container.prototype.layout = function () {
        };

        return container;
    })();

    /*************************** container end **************************/


    /*************************** useful functions begin **************************/
    function debounce(callback, delay) {
        var timer;
        return function () {
            if (timer)
                clearTimeout(timer);
            var context = this;
            var args = arguments;
            timer = setTimeout(function () {
                callback.apply(context, args);
            }, delay);
        }
    }

    function throttle(callback, delay) {
        var last = 0;
        return function () {
            var now = new Date();
            if (now - last > delay) {
                callback.apply(this, arguments);
                last = now;
            }
        }
    }

    function observer(obj, propertyName, value, onPropertyChange) {

        Object.defineProperty(obj, propertyName, {
            configurable: true,
            get: function () {
                return value;
            },
            set: function (newVal) {
                var proceed = true;
                var oldVal = value;
                value = newVal;
                if (oldVal !== newVal && onPropertyChange && typeof onPropertyChange == 'function') {
                    proceed = onPropertyChange.apply(obj, [oldVal, newVal]);
                }
                if (proceed === false)//明确cancel值
                    value = oldVal;
            }
        });
    }

    function resolveFullPath(path) {
        if (typeof path != 'string')
            return null;
        if (path && (path.indexOf('http://') === 0 || path.indexOf('https://') === 0)) {
            return path;
        }

        var fullHost = window.location.protocol + "//" + window.location.host;
        if (path && path.indexOf('/') === 0) {
            return fullHost + path;
        }
        var absolutePath = fullHost + window.location.pathname;
        var reg = new RegExp("\\.\\./", "g");
        var uplayCount = 0;
        var m = path.match(reg);
        if (m) uplayCount = m.length;

        var lastIndex = absolutePath.length - 1;
        var subString = absolutePath.substr(0, lastIndex + 1)
        for (var i = 0; i <= uplayCount; i++) {
            lastIndex = subString.lastIndexOf("/", lastIndex);
            subString = subString.substr(0, lastIndex)
        }
        return subString + "/" + path.replace(reg, "");
    }

    function createGUID() {
        var now = new Date();
        var d = now.getTime();
        var id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            var r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
        });
        return id;
    }

    function createSequenceID() {
        var id = createGUID();
        var now = new Date();
        return now.pattern('yyyyMMddHHmmss') + id.replace(/\-/ig, '').toUpperCase()
    }

    function http(config) {
        return new Promise(function (resolve, reject) {
            var baseUri = (config.baseUri || (window.location.protocol + "//" + window.location.host)).trim('/');
            var url = config.url.trim('/');
            if (url.indexOf('http://') === 0 || url.indexOf('https://') === 0) {
                baseUri = "";
            }
            else {
                url = baseUri + "/" + url;
            }

            var uri = new Uri(url);
            uri.addParams(config.params);
            url = uri.toString();

            var data = "";
            switch (config.method) {
                case 'get':
                case 'head':
                    break;
                case 'put':
                case 'post':
                case 'delete':
                default:
                    data = JSON.stringify(config.data);
                    break;
            };

            $.ajax({
                url: url,
                type: config.method || "get",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                context: config.context || this,
                headers: config.headers,
                timeout: config.timeOut || 60000,
                cache: config.cache || false,
                async: config.async || true,
                xhrFields: {
                    withCredentials: config.withCredentials
                },
                data: data,
                beforeSend: function (xhr) {
                    if (config.beforeSend) return config.beforeSend.apply(this, [xhr]);
                    if (config.showProcessing) $(document.body).process('show');
                    return true;
                },
                success: function (response) {
                    if (response) {
                        if (config.autoMsg && response.message) {
                            $.alert(response.message);
                        }
                    }

                    resolve(response);
                },
                error: function (response) {
                    if (config.autoMsg && response && response.message) {
                        $.alert(response.message);
                    }
                    reject(response);
                },
                complete: function (xhr) {
                    if (config.showProcessing) $(document.body).process('hide');
                    if (config.afterSend) config.afterSend.apply(this, [xhr]);
                }
            });
        });
    }

    function createService(serviceConfig) {
        var proxy = {};
        for (var i = 0; i < serviceConfig.adapters.length; i++) {
            var adapter = serviceConfig.adapters[i];
            var proxyItem = {};

            for (var n = 0; n < adapter.api.length; n++) {
                if (adapter.api[n].url)
                    (function (adapter, api) {
                        var baseUri;

                        var url;
                        if (api.url.indexOf('http://') === 0 || api.url.indexOf('https://') === 0) {
                            baseUri = "";
                            url = api.url.trim('/');
                        }
                        else {
                            baseUri = adapter.host ? ((adapter.host.indexOf('http://') === 0 || adapter.host.indexOf('https://') === 0) ? adapter.host : serviceConfig.defaults.host[adapter.host]) : "";
                            baseUri = baseUri || (window.location.protocol + "//" + window.location.host);
                            url = (adapter.virtualPath && adapter.virtualPath != '/') ? ('/' + adapter.virtualPath.trim('/') + '/' + api.url.trim('/')) : '/' + api.url.trim('/');
                        }

                        var method = api.method || serviceConfig.defaults.method;
                        var withCredentials = api.enableCookies || serviceConfig.defaults.enableCookies;
                        var autoMsg = api.autoMsg || serviceConfig.defaults.autoMsg;
                        var async = api.async || serviceConfig.defaults.async;
                        var timeOut = api.timeOut || serviceConfig.defaults.timeOut;
                        var showProcessing = api.showProcessing || serviceConfig.defaults.showProcessing;
                        var headers = $.extend({}, api.headers || {}, serviceConfig.defaults.headers || {});
                        var params = api.params || {};
                        var data = api.data;

                        if (api.noAjax) {

                            var uri = new Uri(baseUri + url);
                            //uri.addParams(api.params);
                            var webRequest = {
                                fullUri: uri,
                                //baseUri: baseUri,
                                //url: url,
                                method: method,
                                headers: headers,
                                params: params,
                                data: data,
                                toString: function () {
                                    this.fullUri.addParams(this.params);
                                    return this.fullUri.toString();
                                }
                            };
                            proxyItem[api.name] = webRequest;
                        }
                        else {

                            var func = function (request) {
                                request = request || {};
                                var requestUrl = url;
                                var postData;
                                if (typeof data === typeof request.data) {
                                    postData = $.extend({}, data, request.data);
                                }
                                else {
                                    postData = request.data;
                                }

                                if (request && request.routeData) {
                                    for (var key in request.routeData) {
                                        var parkey = `{${key}}`;
                                        requestUrl = requestUrl.replace(parkey, request.routeData[key]);
                                    }
                                }

                                return http({
                                    baseUri: baseUri,
                                    url: requestUrl,
                                    method: method,
                                    async: async,
                                    headers: $.extend({}, headers, request.headers),
                                    withCredentials: withCredentials,
                                    showProcessing: showProcessing,
                                    data: postData,
                                    params: $.extend({}, params, request.params),
                                    timeout: timeOut,
                                    autoMsg: autoMsg,
                                    nowrap: api.nowrap
                                });
                            };
                            func.baseUri = baseUri;
                            func.url = url;
                            func.method = method;
                            func.headers = headers;
                            func.params = params;
                            func.data = data;

                            proxyItem[api.name] = func;
                        }
                    })(adapter, adapter.api[n]);
            }

            proxy[adapter.name] = proxyItem;
        }
        return proxy;
    }

    /*************************** useful functions end **************************/


    return {
        http: http,
        createService: createService,
        createGUID: createGUID,
        createSequenceID: createSequenceID,
        resolveFullPath: resolveFullPath,
        debounce: debounce,
        throttle: throttle,
        observer: observer,
        inherit: inherit,
        recursion: recursion,
        extend: extend,
        Agent: Agent,
        Uri: Uri,
        TaskPool: TaskPool,
        Task: Task,
        Container: Container
    };

})